﻿using System;
using OptimalisationFramework.Interfaces;
using System.IO;

namespace OptimalisationFramework
{
    namespace Problems
    {
        class MinMaxProblem : ITrajectorySearch
        {
            private int[] values;
            private int size;
            private Random r;
            private double adjustRate;
            private int minl, maxl;
            private int max, min;
            private double levelOfCorrectness;
            private object locker;

            public int Maxl
            {
                get { return maxl; }
            }

            public int Minl
            {
                get { return minl; }
            }

            public int Size
            {
                get { return size; }
            }

            public MinMaxProblem(MinMaxProblem m)
            {
                this.min = m.min;
                this.max = m.max;
                this.values = m.values;
                this.adjustRate = m.adjustRate;
                this.size = m.size;
                this.minl = m.minl;
                this.maxl = m.maxl;
                this.levelOfCorrectness = m.levelOfCorrectness;
                this.locker = m.locker;
                r = new Random(size);
            }

            public MinMaxProblem(int aant, double rate, int min, int max, double levelOfCorrectness)
            {
                size = aant;
                this.max = max;
                this.min = min;
                if (rate < 0 || rate > 1 || levelOfCorrectness < 0 || levelOfCorrectness > 1)
                {
                    throw (new Exception("Wrong parameters"));
                }
                values = new int[size];
                r = new Random((int)DateTime.Now.Ticks);
                locker = new object();
                for (int i = 0; i < size; i++)
                {
                    int va = r.Next(min, max);
                    for (int k = 0; k < 2; k++)
                        va = r.Next(min, va);

                    //Console.WriteLine("Value: " + va);
                    values[i] = va;
                }
                values[r.Next(0, size)] = max;
                values[r.Next(0, size)] = min;
                this.levelOfCorrectness = levelOfCorrectness;
                adjustRate = rate;
            }

            public ITrajectorySearch GenerateInitialSolution()
            {
                minl = r.Next(0, size - 1);
                maxl = r.Next(0, size - 1);
                while (values[maxl] < values[minl])
                {
                    maxl = r.Next(0, size - 1);
                }
                return this;
            }


            public ITrajectorySearch AdjustSolution()
            {
                lock (locker)
                {

                    int tempMin = r.Next(0, size - 1);
                    int tempMax = r.Next(0, size - 1);
                    if (values[tempMin] < values[minl])
                    {
                        minl = tempMin;
                    }
                    else if (values[tempMax] < values[minl])
                    {
                        minl = tempMax;
                    }

                    if (values[tempMax] > values[maxl])
                    {
                        maxl = tempMax;
                    }
                    else if (values[tempMin] > values[maxl])
                    {
                        maxl = tempMin;
                    }

                    //Console.WriteLine(values[maxl] + " - " + values[minl]);    
                    return this;
                }
            }

            public int GetMin()
            {
                return values[minl];
            }

            public int GetMax()
            {
                return values[maxl];
            }


            // compare solutions 
            /*
            public static bool operator <(MinMaxProblem s1, MinMaxProblem s2)
            {
                return s1.objectifFunction() < s2.objectifFunction();            
            }

            public static bool operator >(MinMaxProblem s1, MinMaxProblem s2)
            {
                return s1.objectifFunction() > s2.objectifFunction();           
            }
            */
            public bool StopSearch()
            {
                if ((values[maxl] - values[minl]) >= (max - min) * levelOfCorrectness)
                {                    
                    return true;
                }
                return false;
            }

            public double ObjectifFunction()
            {
                return ((double)values[maxl] - (double)values[minl]) / ((double)max - (double)min);
            }


            public void WriteArray()
            {
                for (int i = 0; i < size; i++)
                {
                    Console.Write(values[i] + " ");
                }
                Console.WriteLine();
            }
        }
    }
}
